﻿[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Items.ChoiceItem.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Items.ChoiceItem.debug.js", "application/x-javascript")]

namespace BM.Tools.WebControls.MForm.Controls.Items
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.UI;    
    using System.Xml.XPath;

    using AjaxControlToolkit;

    using BM.Tools.WebControls.MForm.Controls.Helper;    
    using BM.Tools.WebControls.MForm.Controls.Validators;
    using BM.Tools.WebControls.MForm.Generator;    

    /// <summary>
    /// The repeatable offspring item that is created from the <see cref="Choice"/> definition object
    /// </summary>
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.Items.ChoiceItem.js")]
    public class ChoiceItem : OffspringsOwnerItem
    {
        public const string ChoiceItemCssClass = "MForm-Ch";

        private const string ChoiceContainerCssClass = "MForm-ChC";

        private HiddenInput hiddenInput;

        /// <summary>
        /// Initializes a new instance of the <see cref="ChoiceItem"/> class. 
        /// </summary>
        /// <param name="basis">
        /// The basis.
        /// </param>
        /// <param name="index">
        /// The index.
        /// </param>
        public ChoiceItem(Choice basis, int index) : base(basis, index)
        {
            ChoiceBox = new ChoiceBox(this);
            DataBound += SelectChoiceBox;
        }        

        /// <summary>
        /// Gets Basis.
        /// </summary>        
        public new Choice Basis
        {
            get
            {
                return base.Basis as Choice;
            }
        }

        /// <summary>
        /// Gets the choice box, displaying all child item names.
        /// </summary>        
        public ChoiceBox ChoiceBox
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether the item is optional.
        /// </summary>        
        public virtual bool IsOptional
        {
            get
            {
                if (IsOptionalInternal == null)
                {
                    return Basis.IsOptional;
                }

                return IsOptionalInternal.Value;
            }

            set
            {
                IsOptionalInternal = value;
            }
        }

        /// <summary>
        /// Gets or sets the name of the selected items.
        /// </summary>
        public virtual string SelectedItemsName
        {
            get
            {
                return ChoiceBox.SelectedValue;
            }

            set
            {
                ChoiceBox.SelectedValue = value;
            }
        }

        /// <summary>
        /// Gets selected items.
        /// </summary>        
        public virtual IEnumerable<OffspringItem> SelectedItems
        {
            get
            {
                foreach (OffspringItem child in ChildItems)
                {
                    if (SelectedItemsName == child.Name)
                    {
                        yield return child;
                    }
                }                
            }
        }        

        internal bool? IsOptionalInternal
        {
            get
            {
                return ViewState.GetValue<bool?>("isOptional", null);                
            }

            set
            {
                ViewState["isOptional"] = value.Value;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the item should be validated.
        /// </summary>
        protected override bool HasReasonsNotToBeValidated
        {
            get
            {
                if (SelectedItems.Count() == 0 && (IsOptional || (Mode == FormBuilderMode.View && !Basis.Root.ShouldValidateInViewMode)))
                {
                    return true;
                }

                return base.HasReasonsNotToBeValidated;
            }
        }

        /// <summary>
        /// Gets hidden input field that will keep track about the existence of the item between postbacks
        /// </summary>        
        protected virtual HiddenInput HiddenInput
        {
            get
            {
                if (hiddenInput == null)
                {
                    hiddenInput = new HiddenInput(this);
                    hiddenInput.Value = string.Empty;
                }

                return hiddenInput;
            }
        }

        /// <summary>
        /// the method is fired after item is created on postback
        /// </summary>
        internal override void OnPostBack()
        {
            base.OnPostBack();
            SelectedItemsName = Page.Request[ClientID];
        }

        /// <summary>
        /// Appends the resulting xml node of this offspring to the given parent node.
        /// </summary>
        /// <param name="parent">
        /// The parent node. 
        /// </param>
        protected override void AppendXmlToParent(IXPathNavigable parent)
        {
            foreach (var item in SelectedItems.Where(item => item.XmlEditEnabled))
            {
                item.AppendToParent(parent);    
            }            
        }

        /// <summary>
        /// creates inner controls along with the button container,
        /// adds the hidden input,
        /// instantiates the contents template        
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();            
            Controls.AddAt(1, HiddenInput);
            Controls.AddAt(2, ChoiceBox);
        }

        /// <summary>
        /// returns the css classes that are ascribed to this item
        /// </summary>
        /// <returns>
        /// the css classes that are ascribed to this item
        /// </returns>
        protected override string[] InitalizationCssClasses()
        {
            var classes = new List<string>(base.InitalizationCssClasses())
                          {
                                  ChoiceContainerCssClass,
                                  OffspringsOwnerCssClass
                          };
            return classes.ToArray();
        }

        /// <summary>
        /// Adds custom css classes
        /// </summary>
        /// <param name="e">
        /// The event args
        /// </param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (IsOptional)
            {
                CssClasses.Add(LeafItem.OptionalCssClass);
            }            
        }

        /// <summary>
        /// runs the showing and hiding of child items and renders the control
        /// </summary>
        /// <param name="writer">
        /// The writer.
        /// </param>
        protected override void Render(HtmlTextWriter writer)
        {
            ShowHideChildItems();
            base.Render(writer);
        }

        /// <summary>
        /// checks validity of the item against its all constraints
        /// </summary>
        /// <param name="validator">
        /// The validator.
        /// </param>
        /// <returns>
        /// is the item valid
        /// </returns>
        protected override bool ValidateObligatory(RootValidator validator)
        {
            var selectedItems = SelectedItems;
            if (selectedItems.Count() == 0)
            {
                validator.ErrorCauses.Add(new NotSelectedChoiceItemErrorCause(this));
                return false;                
            }

            return selectedItems.Select(item => item.Validate(validator)).All(areSatisfied => areSatisfied);
        }

        private static void ShowHideChildItem(OffspringItem item, bool hide)
        {
            string display = hide ? "none" : string.Empty;
            item.Style.Add("display", display);
            item.Basis.AddButton.Style.Add("display", display);
        }

        private void ShowHideChildItems()
        {
            HiddenInput.Value = SelectedItemsName;            
            foreach (OffspringItem item in ChildItems)
            {
                item.CssClasses.Add(ChoiceItemCssClass);
                ShowHideChildItem(item, item.Name != SelectedItemsName);
            }
        }

        private void SelectChoiceBox(object sender, EventArgs e)
        {
            foreach (var childItem in ChildItems)
            {
                if (childItem.Navigable != null)
                {
                    SelectedItemsName = childItem.Name;
                }
            }
        }
    }
}